#include "config.h"

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/uio.h>
#include <sys/resource.h>
#include <unistd.h>
#include <unistd.h>
#include <stdint.h>
#include <string.h>
#include <semaphore.h>
#include <poll.h> 
#include <pthread.h>
#include <errno.h>

#define DBG_SUBSYS S_LIBCLUSTER

#include "configure.h"
#include "ynet_net.h"
#include "ynet_rpc.h"
#include "job_dock.h"
#include "sysy_lib.h"
#include "ynet_rpc.h"
#include "net_global.h"
#include "net_table.h"
#include "net_tool.h"
#include "net_vip_rpc.h"
#include "net_vip.h"
#include "dbg.h"

#include "sdevent.h"
#include "xnect.h"
#include "ylock.h"
#include "rpc_proto.h"
#include "adt.h"
#include "squeue.h"
#include "cluster.h"

typedef enum {
        NETVIP_RPC_NULL = 0,
        NETVIP_RPC_GETIP_BYVIP,
        NETVIP_RPC_MASTER_SETVIP,
        NETVIP_RPC_MAX,
} netvip_op_t;

typedef struct {
        uint32_t op;
        //uint32_t buflen;
        char buf[0];
} msg_t;

static __request_handler_func__  __request_handler__[NETVIP_RPC_MAX - NETVIP_RPC_NULL];
static char  __request_name__[NETVIP_RPC_MAX - NETVIP_RPC_NULL][__RPC_HANDLER_NAME__ ];


static void __request_get_handler(int op, __request_handler_func__ *func, char *name)
{
        *func = __request_handler__[op - NETVIP_RPC_NULL];
        strcpy(name, __request_name__[op - NETVIP_RPC_NULL]);
}

static void __request_set_handler(int op, __request_handler_func__ func, const char *name)
{
        YASSERT(strlen(name) + 1 < __RPC_HANDLER_NAME__ );
        strcpy(__request_name__[op - NETVIP_RPC_NULL], name);
        __request_handler__[op - NETVIP_RPC_NULL] = func;
}

static void __getmsg(buffer_t *buf, msg_t **_req, int *buflen, char *_buf)
{
        msg_t *req;

        YASSERT(buf->len <= MEM_CACHE_SIZE4K);

        req = (void *)_buf;
        *buflen = buf->len - sizeof(*req);
        mbuffer_get(buf, req, buf->len);

        *_req = req;
}

static int __netvip_srv_getip_byvip(const sockid_t *sockid, const msgid_t *msgid, buffer_t *_buf)
{
        int ret, buflen;
        msg_t *req;
        uint32_t *vip;
        char buf[MAX_BUF_LEN], value[MAX_BUF_LEN];
        int valuelen;

        DBUG("netvip getip vip (%u, %x)\n", msgid->idx, msgid->figerprint);

        __getmsg(_buf, &req, &buflen, buf);

        _opaque_decode(req->buf, buflen, &vip, NULL, NULL);

        ret = nettool_get_ip_byvip(*vip, value, &valuelen);
        if (unlikely(ret)) {
                DWARN("netvip get ip failed ret %d\n", ret);
                GOTO(err_ret, ret);
        }

        rpc_reply(sockid, msgid, value, valuelen);

        return 0;
err_ret:
        return ret;
}

int netvip_rpc_getip_byvip(const nid_t *nid, const uint32_t vip, char *value, int *valuelen)
{
        int ret;
        char *buf = mem_cache_calloc1(MEM_CACHE_4K, PAGE_SIZE);
        uint32_t count;
        msg_t *req;

        req = (void *)buf;
        req->op = NETVIP_RPC_GETIP_BYVIP;

        _opaque_encode(req->buf, &count, &vip, sizeof(vip), NULL);

        ret = rpc_request_wait("netvip_srv_getip_byvip", nid,
                        req, sizeof(*req) + count,
                        value, NULL,
                        MSG_NETVIP, 0, _get_timeout());
        if (unlikely(ret)) {
                GOTO(err_ret, ret);
        }

        *valuelen = strlen(value) + 1; 

        mem_cache_free(MEM_CACHE_4K, buf);

        return 0;
err_ret:
        return ret;
}

static int __netvip_srv_master_setvip(const sockid_t *sockid, const msgid_t *msgid, buffer_t *_buf)
{
        int ret, buflen;
        msg_t *req;
        char *vip;
        char buf[MAX_BUF_LEN];

        DBUG("netvip master setvip (%u, %x)\n", msgid->idx, msgid->figerprint);

        __getmsg(_buf, &req, &buflen, buf);

        _opaque_decode(req->buf, buflen, &vip, NULL, NULL);

        ret = netvip_check_vip(vip);
        if (unlikely(ret)) {
                DWARN("netvip master setvip failed ret %d\n", ret);
                GOTO(err_ret, ret);
        }

        rpc_reply(sockid, msgid, NULL, 0);

        return 0;
err_ret:
        return ret;
}

int netvip_rpc_master_setvip(const nid_t *nid, const char *vip, int len)
{
        int ret;
        char *buf = mem_cache_calloc1(MEM_CACHE_4K, PAGE_SIZE);
        uint32_t count;
        msg_t *req;

        ret = network_connect(nid, NULL, 1, 0);
        if (unlikely(ret))
                GOTO(err_ret, ret);

        req = (void *)buf;
        req->op = NETVIP_RPC_MASTER_SETVIP;

        _opaque_encode(req->buf, &count, vip, len, NULL);

        ret = rpc_request_wait("netvip_srv_master_setvip", nid,
                        req, sizeof(*req) + count,
                        NULL, NULL,
                        MSG_NETVIP, 0, _get_timeout());
        if (unlikely(ret)) {
                GOTO(err_ret, ret);
        }

        mem_cache_free(MEM_CACHE_4K, buf);

        return 0;
err_ret:
        return ret;
}

static void __request_handler(void *arg)
{
        int ret;
        msg_t req;
        sockid_t sockid;
        msgid_t msgid;
        buffer_t buf;
        __request_handler_func__ handler;
        char name[MAX_NAME_LEN];

        request_trans(arg, &sockid, &msgid, &buf, NULL);

        if (buf.len < sizeof(req)) {
                ret = EINVAL;
                GOTO(err_ret, ret);
        }

        mbuffer_get(&buf, &req, sizeof(req));

        DINFO("new job op %u\n", req.op);

        //handler = __request_handler__[req.op - NETVIP_RPC_MAX];
        __request_get_handler(req.op, &handler, name);
        if (handler == NULL) {
                ret = ENOSYS;
                DWARN("error op %u\n", req.op);
                GOTO(err_ret, ret);
        }

        schedule_task_setname(name);

        ret = handler(&sockid, &msgid, &buf);
        if (unlikely(ret))
                GOTO(err_ret, ret);

        mbuffer_free(&buf);

        return ;
err_ret:
        mbuffer_free(&buf);
        rpc_reply_error(&sockid, &msgid, ret);
        return;
}

int netvip_rpc_init()
{
        __request_set_handler(NETVIP_RPC_GETIP_BYVIP, __netvip_srv_getip_byvip, "netvip_srv_getip_byvip");
        __request_set_handler(NETVIP_RPC_MASTER_SETVIP, __netvip_srv_master_setvip, "netvip_srv_master_setvip");

        rpc_request_register(MSG_NETVIP, __request_handler, NULL);

        return 0;
}
